package com.jiaai.shop.util.redis.aop;


import cn.jiguang.common.utils.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import com.jiaai.shop.util.redis.RedisUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Aspect
@Component
public class RedisAspect {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 没有异常, 正常的调用方法后, 删除redis里的数据
     * @param jp
     * @param evict
     */
    @AfterReturning(value = "@annotation(evict)")
    public void cacheClear(JoinPoint jp, RedisEvict evict){
        String[] keys = evict.keys();

        int index = evict.index();

        String field = jp.getArgs()[index].toString();

        if (evict.isFieldOnly()){
            redisUtil.hashDel(0, keys[0], field.concat("_"));
        }else {
            redisUtil.delKey(0, keys);
        }

    }

    @Around(value = "@annotation(cache)")
    public Object cacheAround(ProceedingJoinPoint jp, RedisCache cache) throws Throwable{
        //获取返回的类型, or泛型类型
        Class modelType = cache.type();
        //获取主key-->用于del命令
        String primaryKey = cache.key();
        //失效时间
        int expiredTime = cache.expiredTime();
        //方法的名称
        String methodName = jp.getSignature().getName();
        //所有参数
        Object[] args = jp.getArgs();
        //redis的key
        String redisKey = primaryKey.concat("_").concat(methodName);
        //key里的hashKey
        String fieldKey = genFieldKey(args);
        String value = null;
        try {
            value = redisUtil.hashGet(0, redisKey, fieldKey);
        }catch (Exception e){}

        Object result = null;
        if (StringUtils.isEmpty(value)){
            // 调用数据库查询方法
            result = jp.proceed(args);
            // 序列化查询结果
            String json = serialize(result);
            // 序列化结果放入缓存
            try {
                redisUtil.hashSet(0,redisKey,fieldKey, json, expiredTime);
            }catch (Exception e){}
            return result;
        }else {
            // 得到被代理方法的返回值类型
            Class returnType = ((MethodSignature) jp.getSignature()).getReturnType();
            // 反序列化从缓存中拿到的json
            result = deserialize(value, returnType, modelType);
            return result;
        }
    }

    private String genFieldKey(Object[] args) {
        StringBuilder sb = new StringBuilder();
        if (args == null || args.length ==0){
            return "default";
        }
        for (Object obj : args) {
            if (obj != null) {
                String temp = obj.toString();
                if (temp.lastIndexOf("@") != -1) {//object.toString()方法, 这是一个对象
                    JSONObject o = JSONObject.parseObject(JSONObject.toJSONString(obj));
                    if (o.values()!=null && o.values().size()>0){
                        for (Object s : o.values()) {
                            sb.append(s).append("_");
                        }
                    }
                }else {
                    sb.append(obj).append("_");
                }
            }
        }

        return sb.toString();
    }

    protected String serialize(Object target) {
        return JSONObject.toJSONString(target);
    }

    protected Object deserialize(String jsonString, Class clazz, Class modelType) {
        // 序列化结果应该是List对象
        if (clazz.isAssignableFrom(List.class)) {
            return JSONObject.parseArray(jsonString, modelType);
        }else if (clazz.isAssignableFrom(JSONArray.class)){
            return JSONObject.parseArray(jsonString);
        }
        // 序列化结果是普通对象
        return JSONObject.parseObject(jsonString, clazz);
    }



}
